package com.hh.jwtdemo.interceptor;

import com.hh.jwtdemo.annotaion.EncryptedField;
import com.hh.jwtdemo.utils.FieldCryptoUtil;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Properties;

/**
 * Mybatis拦截器，用于加密和解密数据库字段,字段添加@EncryptedField
 */

@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class})
})
public class EncryptInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];

        // 加密处理（INSERT/UPDATE）
        if (SqlCommandType.INSERT == ms.getSqlCommandType()
                || SqlCommandType.UPDATE == ms.getSqlCommandType()) {
            processFields(parameter, true);
        }

        Object result = invocation.proceed();

        // 解密处理（SELECT）
        if (SqlCommandType.SELECT == ms.getSqlCommandType() && result instanceof List) {
            for (Object obj : (List<?>) result) {
                processFields(obj, false);
            }
        }
        return result;
    }

    private void processFields(Object obj, boolean isEncrypt) throws Exception {
        if (obj == null) return;

        Class<?> clazz = obj.getClass();
        MetaObject metaObject = SystemMetaObject.forObject(obj);

        while (clazz != null) {
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(EncryptedField.class)) {
                    String fieldName = field.getName();
                    Object value = metaObject.getValue(fieldName);
                    if (value instanceof String) {
                        String processedValue = isEncrypt ?
                                FieldCryptoUtil.encrypt((String) value) :
                                FieldCryptoUtil.decrypt((String) value);
                        metaObject.setValue(fieldName, processedValue);
                    }
                }
            }
            clazz = clazz.getSuperclass(); // 处理父类字段
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}